/********************************************************************************
 * Copyright(c) 2020-2025 VINCENT_WY All rights reserved.
 * - Filename
 * - Author  Vincent
 * - Version V1.0.0
 * - Date    2021/09/15
 * - Brief
 * - FunctionList:
 ******************************************************************************
 * History:
 *
 *
 *
 ******************************************************************************
 */
#include "SyncUdpClient.h"
#include <fstream>
#include <iostream>
#include <string>
#include <strings.h>

/* parama define describe
 * -----------------------------------------------------*/
/* class describe -----------------------------------------------------*/
namespace vudp {
vudpClient::vudpClient(const int &port) : _listenPort(port) {
  std::cout << "[SyncClient]: udp client create,port: " << _listenPort
            << std::endl;
}

vudpClient::~vudpClient() {
  _isExit = true;
  close(_udpFd);
  if ((_udpClientReciveThread != nullptr) &&
      _udpClientReciveThread->joinable()) {
    _udpClientReciveThread->join();
  }
  std::cout << "[SyncClient]: Destroyed...!" << std::endl;
}

void vudpClient::vudpClientStart() {
  _isExit = false;
  this->_udpClientReciveThread.reset(
      new std::thread(std::bind(&vudpClient::udpClientReciveLoop, this)));
}

void vudpClient::responseCallback(
    std::function<void(std::string &)> response_callback) {
  responseCallBack = response_callback;
}

void vudpClient::udpClientReciveLoop() {
  /*local address */
  struct sockaddr_in m_localAddr;
  bzero(&m_localAddr, sizeof(struct sockaddr_in));
  m_localAddr.sin_family = AF_INET;
  m_localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  m_localAddr.sin_port = htons(_listenPort);

  /* broadcast address */
  struct sockaddr_in m_broadCastAddr;
  bzero(&m_broadCastAddr, sizeof(struct sockaddr_in));
  m_broadCastAddr.sin_family = AF_INET;
  m_broadCastAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  m_broadCastAddr.sin_port = htons(_listenPort);

  if ((_udpFd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
    std::cout << "[UDP CLIENT]: socket error !" << std::endl;
    return;
  }
  if (bind(_udpFd, (struct sockaddr *)&(m_localAddr),
           sizeof(struct sockaddr_in)) == -1) {
    std::cout << "[UDP CLIENT]: bind error !" << std::endl;
    return;
  }
  /* timeout*/
  struct timeval timeOut;
  timeOut.tv_sec = 2;
  timeOut.tv_usec = 0;
  setsockopt(_udpFd, SOL_SOCKET, SO_RCVTIMEO, &timeOut, sizeof(timeOut));

  int len = sizeof(sockaddr_in);
  char m_recviceBuff[128];
  while (!_isExit) {
    int receivePacketLen =
        recvfrom(_udpFd, m_recviceBuff, sizeof(m_recviceBuff), 0,
                 (struct sockaddr *)&m_broadCastAddr, (socklen_t *)&len);
    if (receivePacketLen < 0 && errno == EAGAIN) {
      // std::cout << "[UDP CLIENT]: recive error!" << std::endl;
    } else {
      if (responseCallBack != nullptr) {
        std::string m_reciveString = m_recviceBuff;
        responseCallBack(m_reciveString);
        bzero(m_recviceBuff, sizeof(m_recviceBuff));
      }
    }
  }
}
} // namespace vudp

/************************ (.cpp) END OF FILE
 * ************************************/